package com.jeequan.jeepay.mgr.service;


import cn.hutool.core.collection.CollectionUtil;
import com.jeequan.jeepay.core.cache.RedisUtil;
import com.jeequan.jeepay.core.entity.OrderStatisticsDept;
import com.jeequan.jeepay.core.entity.PayOrderFlow;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.mgr.rqrs.*;
import com.jeequan.jeepay.service.impl.OrderStatisticsDeptService;
import com.jeequan.jeepay.service.impl.PayOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.text.MessageFormat;
//import java.time.LocalDate;
//import java.time.LocalDateTime;
//import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ReportingService {

    @Autowired
    private OrderStatisticsDeptService statisticsDeptService;

    @Autowired
    private PayOrderService payOrderService;

    @Autowired
    private FlowOrderService flowOrderService;

    @Value(value = "${qiDi.gateWay.url}")
    private String gateWay;

    @Value(value = "${qiDi.gateWay.secret-key}")
    private String secretKey;

    @Resource(name = "customRestTemplate")
    private RestTemplate restTemplate;

    private static final String DEALTYPE_DEPARTMENTAL = "DEPARTMENTAL";//部门
    private static final String DEALTYPE_RENT = "RENT";//月租

    /**
     * 根据月份查找到账单
     *
     * @param timeStart 订单开始时间
     * @param timeEnd   订单结束时间
     * @return List<AccountForTenantRq>
     */
    public List<AccountForTenantRq> getAccountForTenants(String timeStart, String timeEnd) {

        List<AccountForTenantRq> accountRQList = new ArrayList<>();

        List<OrderStatisticsDept> orderStatisticsDeptList = payOrderService.selectOrderCountByDept(timeStart, timeEnd, this.DEALTYPE_DEPARTMENTAL);
        if (!CollectionUtil.isEmpty(orderStatisticsDeptList)) {
            orderStatisticsDeptList.forEach(item -> {
                //查询部门信息
                MutablePair<String, String> mutablePair = getDept(item.getDeptId());
                item.setDeptName(mutablePair.right);
                item.setParentName(mutablePair.left);
                item.setParentId(String.valueOf(mutablePair.left.hashCode()));
            });
        }

        //按公司，消费类别两层分组
        Map<String, Map<String, List<OrderStatisticsDept>>> companyMap = orderStatisticsDeptList.stream()
                .collect(Collectors.groupingBy(OrderStatisticsDept::getParentName,
                        Collectors.groupingBy(OrderStatisticsDept::getAppName)));

        //遍历公司列表
        companyMap.entrySet().forEach(entry -> {
                    AccountForTenantRq accountRQ = new AccountForTenantRq();
                    accountRQ.setAccountTime(new Date());
                    accountRQ.setGroupName(entry.getKey());
                    accountRQ.setAccountForDepartmentRqs(new ArrayList<AccountForDepartmentRq>());

                    //公司下的所有类别统计
                    Map<String, Double> cmpAccountDetailMap = new HashMap<>();
                    entry.getValue().entrySet().forEach(sub -> {
                        cmpAccountDetailMap.put(sub.getKey(), sub.getValue().stream().mapToDouble(OrderStatisticsDept::getAmount).sum());
                    });
                    accountRQ.setCmpAccountDetailMap(cmpAccountDetailMap);

                    //部门消费分类列表统计
                    List<AccountForDepartmentRq> accountForDepartmentRqs = new ArrayList<>();

                    //拓展type没有分类的情况
                    Map<String, List<OrderStatisticsDept>> orderStaticDepatMapNoType = entry.getValue().entrySet().stream()
                            .collect(Collectors.toMap(
                                    Map.Entry::getKey,
                                    subEntry -> subEntry.getValue().stream()
                                            .filter(obj -> StringUtils.isEmpty(obj.getExtType()))
                                            .collect(Collectors.toList())
                            ));

                    orderStaticDepatMapNoType.entrySet().forEach(sub -> {

                        if(CollectionUtil.isNotEmpty(sub.getValue())) {

                            AccountForDepartmentRq accountForDepartmentRq = new AccountForDepartmentRq();
                            accountForDepartmentRq.setAppName(sub.getKey());

                            Map<String, Double> accountDeptMap = sub.getValue()
                                    .stream()
                                    .filter(item -> StringUtils.isEmpty(item.getExtType()))
                                    .collect(Collectors.groupingBy(OrderStatisticsDept::getDeptName
                                            , Collectors.summingDouble(OrderStatisticsDept::getAmount)));

                            accountForDepartmentRq.setOrgAccountDetailMap(accountDeptMap);
                            accountForDepartmentRq.setAccountTime(new Date());
                            accountForDepartmentRq.setTotalAccountForApp(sub.getValue().stream().mapToDouble(OrderStatisticsDept::getAmount).sum());
                            accountForDepartmentRqs.add(accountForDepartmentRq);
                        }

                    });


                    //拓展type有分类的情况
                    Map<String, List<OrderStatisticsDept>> filteredMap = entry.getValue().entrySet().stream()
                            .collect(Collectors.toMap(
                                    Map.Entry::getKey,
                                    subEntry -> subEntry.getValue().stream()
                                            .filter(obj -> !StringUtils.isEmpty(obj.getExtType()))
                                            .collect(Collectors.toList())
                            ));

                    filteredMap.entrySet().forEach(sub -> {

                        if(CollectionUtil.isNotEmpty(sub.getValue())){

                            AccountForDepartmentRq accountForDepartmentRq = new AccountForDepartmentRq();
                            accountForDepartmentRq.setAppName(sub.getKey());

                            Map<String, Map<String, Double>> accountTypeDeptMap = sub.getValue()
                                    .stream()
                                    .filter(item -> !StringUtils.isEmpty(item.getExtType()))
                                    .collect(Collectors.groupingBy(OrderStatisticsDept::getDeptName
                                            , Collectors.groupingBy(OrderStatisticsDept::getExtType
                                                    , Collectors.summingDouble(OrderStatisticsDept::getAmount))));

                            accountForDepartmentRq.setTypeDetailMap((accountTypeDeptMap));
                            accountForDepartmentRq.setAccountTime(new Date());
                            accountForDepartmentRq.setTotalAccountForApp(sub.getValue().stream().mapToDouble(OrderStatisticsDept::getAmount).sum());
                            accountForDepartmentRqs.add(accountForDepartmentRq);
                        }
                    });

                    accountRQ.getAccountForDepartmentRqs().addAll(accountForDepartmentRqs);
                    accountRQ.setTotalAccountForTenant(accountForDepartmentRqs.stream().mapToDouble(AccountForDepartmentRq::getTotalAccountForApp).sum());
                    accountRQList.add(accountRQ);
                }
        );
        return accountRQList;
    }


    /**
     * 根据月份查找月租账单
     *
     * @param timeStart 订单开始时间
     * @param timeEnd   订单结束时间
     * @return List<AccountForMchRq>
     */
    public Map<String, Object> getRentOrder(String timeStart, String timeEnd, String dealType, String appArray) {

        Map<String, Object> model = new HashMap<>();

        List<AccountForMchRq> accountForMchRqs = new ArrayList<>();

        List<PayOrderFlow> payOrderFlows = flowOrderService.getRentMapList(timeStart, timeEnd, dealType, appArray);

        Map<String, Double> typeMap = payOrderFlows.stream().filter(x -> !StringUtils.isEmpty(x.getDealType()))
                .collect(Collectors.groupingBy(PayOrderFlow::getDealType
                        , Collectors.summingDouble(PayOrderFlow::getAmount)));

        model.put("total", typeMap.values().stream().mapToDouble(Double::doubleValue).sum());
        model.put("typeList", typeMap);

        Map<String, Double> accountMap = payOrderFlows.stream().filter(x -> !StringUtils.isEmpty(x.getDealType()))
                .collect(Collectors.groupingBy(item->{
                            return  StringUtils.isEmpty(item.getExtType())? item.getAppName():item.getAppName().concat("-").concat(item.getExtType());
                        }
                        , Collectors.summingDouble(PayOrderFlow::getAmount)));

        Map<String, Map<String, List<PayOrderFlow>>> orderFlowMap =
                payOrderFlows.stream().filter(x -> !StringUtils.isEmpty(x.getDealType()))
                        .collect(Collectors.groupingBy(item->{
                                return  StringUtils.isEmpty(item.getExtType())? item.getAppName():item.getAppName().concat("-").concat(item.getExtType());
                                }
                                , Collectors.groupingBy(PayOrderFlow::getDealType)));

        orderFlowMap.entrySet().forEach(sub -> {

            AccountForMchRq accountForMchRq = new AccountForMchRq();
            accountForMchRq.setAccountTime(new Date());
            accountForMchRq.setAppName(sub.getKey());
            accountForMchRq.setTotalAccountForApp(accountMap.get(sub.getKey()));

            List<OrderFlowForPay> orderFlowForPays = new ArrayList<>();
            sub.getValue().entrySet().forEach(item -> {

                OrderFlowForPay orderFlowForPay = new OrderFlowForPay();
                orderFlowForPay.setTypeName(item.getKey());
                orderFlowForPay.setTotalAccountForDealType(item.getValue().stream().mapToDouble(PayOrderFlow::getAmount).sum());
                orderFlowForPays.add(orderFlowForPay);
            });

            accountForMchRq.setOrderFlowForPays(orderFlowForPays);
            accountForMchRqs.add(accountForMchRq);
        });

        model.put("accountForMchRqs", accountForMchRqs);
        return model;
    }


    /**
     * 根据部门Id得到部门信息
     *
     * @param deptId
     * @return MutablePair<String, Object>
     */
    public MutablePair<String, String> getDept(String deptId) {

        String[] nameArray;
        String organization = RedisUtil.getString(deptId);//先去缓存中查一下
        if (organization == null || organization.isEmpty()) {
            HttpHeaders headers = new HttpHeaders();
            headers.add("X-API-KEY", secretKey);
            headers.setContentType(MediaType.APPLICATION_JSON);

            HttpEntity<String> request = new HttpEntity<String>(null, headers);
            try{

                ResponseEntity<Map> responseMap = restTemplate.exchange(gateWay + MessageFormat.format("/groups/{0}", deptId), HttpMethod.GET, request, Map.class);

                if (responseMap.getStatusCode().equals(HttpStatus.OK)) {

                    Map<String, Object> responseBody = responseMap.getBody();
                    if (!responseBody.isEmpty() && responseBody.containsKey("path")) {

                        String fullPath = String.valueOf(responseBody.get("path"));

                        RedisUtil.setString(deptId, fullPath, 30, TimeUnit.MINUTES);

                        nameArray = StringUtils.split(fullPath, "/");
                        return MutablePair.of(nameArray[0], nameArray[1]);
                    }
                }
            }catch (Exception ex){
                return MutablePair.of("未知", "未知");
            }

        } else {
            nameArray = StringUtils.split(organization, "/");
            return MutablePair.of(nameArray[0], nameArray[1]);
        }
        return MutablePair.of("", "");
    }


}
